﻿using Cassandra;
using Cassandra.Data.Linq;
using dreamwork.core.Extensions;
using dreamwork.core.Infrastructure.Data.Cassandra;
using Dreamwork.Core.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace dreamwork.exam.api.Infrastructure.Cassandra
{
	public class CanssandraRepository<TEntity> : ICanssandraRepository<TEntity> where TEntity : IDataModel<Guid>
	{
		private readonly string _keyspace;
		private readonly ISession _session;
		private readonly Table<TEntity> _models;
		private readonly ILogger<CanssandraRepository<TEntity>> _logger;
		public CanssandraRepository(ICluster cluster, ILogger<CanssandraRepository<TEntity>> logger, IConfiguration configuration)
		{
			_logger = logger;
			_keyspace = configuration["Cassandra:keyspace"];
			_session = cluster.Connect(_keyspace);
			_models = new Table<TEntity>(_session);
		}
		public async Task AddAsync(TEntity model)
		{
			await _models.Insert(model).ExecuteAsync();
		}

		public async Task<IEnumerable<TEntity>> GetAllAsync()
		{
			return await _models.ExecuteAsync();
		}

		public async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> selector)
		{
			return await _models.FirstOrDefault(selector).ExecuteAsync();
		}

		public async Task<TEntity> GetAsync(Guid id)
		{
			return await _models.FirstOrDefault(x => x.Id == id).ExecuteAsync();
		}

		public async Task<IEnumerable<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> selector)
		{
			return await _models.Where(selector).ExecuteAsync();
		}

		public async Task<bool> RemoveAllAsync()
		{
			StringBuilder cql = new StringBuilder($"Truncate  \"{_keyspace}\".\"{typeof(TEntity).Name}\" ");
			var ps = _session.Prepare(cql.ToString());
			var statement = ps.Bind();
			await _session.ExecuteAsync(statement);
			//var models = await _models.ExecuteAsync();
			//foreach (var model in models)
			//{
			//	var modelId = model.Id;
			//	await _models.Where(x => x.Id == modelId)
			//   .Delete().ExecuteAsync();
			//}

			return true;
		}

		public async Task<bool> RemoveAsync(Guid id)
		{
			await _models.Where(x => x.Id == id)
						.Delete()
						.ExecuteAsync();
			return true;
			//StringBuilder cql = new StringBuilder($"DELETE FROM Customers \"{_keyspace}\".\"{typeof(TEntity).Name}\" ");
			//cql.Append(" WHERE  \"Id\" = ?");
			//var ps = _session.Prepare(cql.ToString());
			//var statement = ps.Bind(id);
			//await _session.ExecuteAsync(statement);
		}

		public async Task<bool> UpdateAsync(TEntity model)
		{
			var properties = model.GetMemberNames().Select(x => $"\"{x}\"");

			StringBuilder cql = new StringBuilder($"UPDATE   \"{_keyspace}\".\"{typeof(TEntity).Name}\" SET ");
			cql.Append(string.Join(",", properties.Select(x => $"{x} = ?")));
			cql.Append(" WHERE \"Id\" = ?");

			var ps = _session.Prepare(cql.ToString());
			var values = model.GetType().GetProperties().OrderBy(x => x.Name)?
				.Where(y => y.Name != nameof(model.Id))?
				.Select(x => x.GetValue(model));
			var statement = ps.Bind(model.GetMemberValues(), model.Id);
			await _session.ExecuteAsync(statement);

			//var modelId = model.Id;
			//await _models.Where(x => x.Id == modelId)
			//			 .Select(ExamUser => model.Id)
			//			 .Update()
			//			 .ExecuteAsync();

			return true;

		}
	}
}
